home *** CD-ROM | disk | FTP | other *** search
Wrap
# Source Generated with Decompyle++ # File: in.pyo (Python 2.3) import os import calendar import time import copy from wxPython.wx import * from wxPython.grid import * from wxPython.lib.mixins.listctrl import wxColumnSorterMixin, wxListCtrlAutoWidthMixin from wxPython.lib.intctrl import * from wxPython.lib.maskededit import wxMaskedTextCtrl from wxPython.html import * import common import gui import calendarcontrol import helpids import comscan import comdiagnose import brewcompressedimage class PhoneDataTable(wxPyGridTableBase): CURRENTFILEVERSION = 1 numbertypetab = ('Home', 'Home2', 'Office', 'Office2', 'Mobile', 'Mobile2', 'Pager', 'Fax', 'Fax2', 'None') typesnames = ('type1', 'type2', 'type3', 'type4', 'type5') typestypename = wxGRID_VALUE_CHOICE + ':' + ','.join(numbertypetab) groupnames = ('group',) grouptypenamebase = wxGRID_VALUE_CHOICE + ':' intnames = ('msgringtone', 'ringtone', 'serial1', 'serial2') boolnames = ('secret',) blankentry = { 'name': '', 'group': 0, 'type1': 0, 'type2': 0, 'type3': 0, 'type4': 0, 'type5': 0, 'number1': '', 'number2': '', 'number3': '', 'number4': '', 'number5': '', 'email1': '', 'email2': '', 'email3': '', 'memo': '', 'msgringtone': 0, 'ringtone': 0, 'secret': False, 'serial1': 0, 'serial2': 0, 'url': '', '?offset00f': 0, '?offset028': 0, '?offset111': 0, '?offset20c': 0 } def __init__(self, mainwindow): wxPyGridTableBase.__init__(self) self.mainwindow = mainwindow self.numrows = 0 self.numcols = 0 self.labels = [] self.roworder = [] self._data = { } self.needswrite = False self.sequence = 65535 self.groupdict = { 0: { 'name': 'No Group', 'icon': 0 }, 1: { 'name': 'Family', 'icon': 1 }, 2: { 'name': 'Friends', 'icon': 2 }, 3: { 'name': 'Colleagues', 'icon': 3 }, 4: { 'name': 'Business', 'icon': 4 }, 5: { 'name': 'School', 'icon': 5 } } self.buildgrouptypename(self.groupdict) def OnIdle(self, _): if self.needswrite: self.populatefs(self.getdata({ })) self.needswrite = False def getdata(self, dict): dict['phonebook'] = self._data.copy() dict['groups'] = self.groupdict.copy() return dict def setstandardlabels(self): self.addcolumn('name') self.addcolumn('group') for i in range(1, 6): self.addcolumn('type' + `i`) self.addcolumn('number' + `i`) def addcolumn(self, name): self.labels.append(name) msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_COLS_APPENDED, 1) self.GetView().ProcessTableMessage(msg) def clear(self): oldr = self.numrows self.numrows = 0 msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, oldr) if oldr: self.GetView().ProcessTableMessage(msg) def OnDelete(self, rows): rows.sort() rows.reverse() for row in rows: del self._data[self.roworder[row]] del self.roworder[row] self.numrows -= 1 msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1) self.GetView().ProcessTableMessage(msg) if len(rows): self.needswrite = True def OnAdd(self, currow): self.sequence += 1 while self.sequence in self._data: self.sequence += 1 continue self self._data[self.sequence] = self.blankentry.copy() if currow + 1 == self.numrows: msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1) self.roworder.append(self.sequence) else: msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, currow + 1, 1) self.roworder[currow + 1:currow + 1] = [ self.sequence] self.numrows += 1 self.GetView().ProcessTableMessage(msg) self.needswrite = True def getcolumn(self, name): if len(self.labels) == 0: self.setstandardlabels() if name not in self.labels: self.addcolumn(name) return self.labels.index(name) def populatefs(self, dict): self.thedir = self.mainwindow.phonebookpath try: os.makedirs(self.thedir) except: pass if not os.path.isdir(self.thedir): raise Exception("Bad directory for phonebook '" + self.thedir + "'") for f in os.listdir(self.thedir): os.remove(os.path.join(self.thedir, f)) d = { } d['phonebook'] = dict['phonebook'] if dict.has_key('groups'): d['groups'] = dict['groups'] common.writeversionindexfile(os.path.join(self.thedir, 'index.idx'), d, self.CURRENTFILEVERSION) return dict def getfromfs(self, dict): self.thedir = self.mainwindow.phonebookpath try: os.makedirs(self.thedir) except: pass if not os.path.isdir(self.thedir): raise Exception("Bad directory for phonebook '" + self.thedir + "'") if os.path.exists(os.path.join(self.thedir, 'index.idx')): d = { 'result': { } } common.readversionedindexfile(os.path.join(self.thedir, 'index.idx'), d, self.versionupgrade, self.CURRENTFILEVERSION) dict.update(d['result']) else: dict['phonebook'] = { } dict['groups'] = self.groupdict return dict def populate(self, dict): self.clear() pb = dict['phonebook'] k = pb.keys() k.sort() self._data = pb.copy() self.roworder = k oldrows = self.numrows self.numrows = len(k) msg = None if self.numrows > oldrows: msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, self.numrows - oldrows) elif self.numrows < oldrows: msg = wxGridTableMessage(self, wxGRIDTABLE_NOTIFY_ROWS_DELETED, self.numrows, oldrows - self.numrows) if msg is not None: self.GetView().ProcessTableMessage(msg) cols = [] for e in pb: keys = pb[e].keys() for k in keys: if k not in cols: cols.append(k) continue cols.sort() k2 = [] for c in cols: if c[0] == '?': k2.append(c) continue self.getcolumn(c) k2.sort() for c in k2: self.getcolumn(c) self.GetView().FitInside() if dict.has_key('groups'): self.buildgrouptypename(dict['groups']) def versionupgrade(self, dict, version): if version == 0: version = 1 def buildgrouptypename(self, dict): self.grouptypename = self.grouptypenamebase keys = dict.keys() keys.sort() [] += []([ dict[k]['name'] for k in keys ]) self.groupdict = dict.copy() def GetNumberRows(self): return len(self.roworder) def GetNumberCols(self): return len(self.labels) def IsEmptyCell(self, row, col): return False def GetValue(self, row, col): celldata = self._data[self.roworder[row]][self.labels[col]] try: if self.labels[col] in self.typesnames: return self.numbertypetab[celldata] elif self.labels[col] in self.groupnames: if self.groupdict.has_key(celldata): return self.groupdict[celldata]['name'] return 'Group #' + `celldata` return celldata except: print 'bad request', row, self.labels[col] return '' def GetTypeName(self, row, col): if self.labels[col] in self.typesnames: return self.typestypename elif self.labels[col] in self.intnames or self.labels[col][0] == '?': return wxGRID_VALUE_NUMBER elif self.labels[col] in self.boolnames: return wxGRID_VALUE_BOOL elif self.labels[col] in self.groupnames: return self.grouptypename return wxGRID_VALUE_STRING + ':50' def SetValue(self, row, col, value): if self.labels[col] in self.typesnames: for i in range(0, len(self.numbertypetab)): if value == self.numbertypetab[i]: value = i break continue elif self.labels[col] in self.groupnames: for i in self.groupdict: if value == self.groupdict[i]['name']: value = i break continue print 'SetValue', row, col, `value` self._data[self.roworder[row]][self.labels[col]] = value if self.labels[col] == 'name': self.GetView().GetGridRowLabelWindow().Refresh() self.needswrite = 1 def GetColLabelValue(self, col): return self.labels[col] def GetRowLabelValue(self, row): return self._data[self.roworder[row]]['name'] def CanGetValueAs(self, row, col, typename): return True def CanSetValueAs(self, row, col, typename): return self.CanGetValueAs(row, col, typename) class PhoneGrid(wxGrid): def __init__(self, mainwindow, parent, id = -1, *args, **kwargs): apply(wxGrid.__init__, (self, parent, id) + args, kwargs) self.mainwindow = mainwindow self.table = PhoneDataTable(mainwindow) self.SetTable(self.table, True) self.table.setstandardlabels() EVT_IDLE(self, self.table.OnIdle) EVT_GRID_CELL_LEFT_DCLICK(self, self.OnLeftDClick) EVT_KEY_DOWN(self, self.OnKeyDown) def OnKeyDown(self, event): if event.KeyCode() != WXK_RETURN: event.Skip() return None if event.ControlDown(): event.Skip() return None self.DisableCellEditControl() success = self.MoveCursorRight(event.ShiftDown()) def OnLeftDClick(self, _): if self.CanEnableCellControl(): self.EnableCellEditControl() def OnDelete(self, _ = None): print 'delete - selected cells=', self.GetSelectedCells() rows = self.GetSelectedRows() self.table.OnDelete(rows) def OnAdd(self, _ = None): print 'add, cursor at row', self.GetGridCursorRow() self.table.OnAdd(self.GetGridCursorRow()) def clear(self): self.table.clear() def getdata(self, dict): self.table.getdata(dict) def populatefs(self, dict): return self.table.populatefs(dict) def populate(self, dict): return self.table.populate(dict) def getfromfs(self, dict): return self.table.getfromfs(dict) class LogWindow(wxPanel): def __init__(self, parent): wxPanel.__init__(self, parent, -1, style = wxNO_FULL_REPAINT_ON_RESIZE) self.tb = wxTextCtrl(self, 1, style = wxTE_MULTILINE | wxTE_RICH2 | wxTE_READONLY | wxNO_FULL_REPAINT_ON_RESIZE | wxTE_DONTWRAP) f = wxFont(10, wxMODERN, wxNORMAL, wxNORMAL) ta = wxTextAttr(font = f) self.tb.SetDefaultStyle(ta) self.sizer = wxBoxSizer(wxVERTICAL) self.sizer.Add(self.tb, 1, wxEXPAND) self.SetSizer(self.sizer) self.SetAutoLayout(True) self.sizer.Fit(self) EVT_IDLE(self, self.OnIdle) self.outstandingtext = '' def OnIdle(self, _): if len(self.outstandingtext): self.tb.AppendText(self.outstandingtext) self.outstandingtext = '' self.tb.ScrollLines(-1) def log(self, str): now = time.time() t = time.localtime(now) self.outstandingtext += '%d:%02d:%02d.%03d %s\r\n' % (t[3], t[4], t[5], int((now - int(now)) * 1000), str) def logdata(self, str, data): hd = '' if data is not None: hd = 'Data - ' + `len(data)` + ' bytes\n' + common.datatohexstring(data) self.log('%s %s' % (str, hd)) class GetPhoneDialog(wxDialog): strings = ('PhoneBook', 'Calendar', 'Wallpaper', 'Ringtone') NOTREQUESTED = 0 MERGE = 1 OVERWRITE = 2 HELPID = helpids.ID_GET_PHONE_DATA def __init__(self, frame, title, id = -1): wxDialog.__init__(self, frame, id, title, style = wxCAPTION | wxSYSTEM_MENU | wxDEFAULT_DIALOG_STYLE) gs = wxFlexGridSizer(6, 4, 5, 10) gs.AddGrowableCol(1) gs.AddMany([ (wxStaticText(self, -1, 'Get'), 0, wxEXPAND), (wxStaticText(self, -1, 'Type'), 0, wxEXPAND), (wxStaticText(self, -1, 'Add'), 0, wxEXPAND), (wxStaticText(self, -1, 'Replace'), 0, wxEXPAND)]) self.cb = [] self.rb = [] for i in self.strings: self.cb.append(wxCheckBox(self, -1, '')) gs.Add(self.cb[-1], 0, wxEXPAND) gs.Add(wxStaticText(self, -1, i), 0, wxEXPAND | wxALIGN_CENTER_VERTICAL) self.rb.append([ wxRadioButton(self, -1, '', style = wxRB_GROUP), wxRadioButton(self, -1, '')]) gs.Add(self.rb[-1][0], 0, wxEXPAND | wxALIGN_CENTRE) gs.Add(self.rb[-1][1], 0, wxEXPAND | wxALIGN_CENTRE) self.rb[-1][0].Enable(False) self.rb[-1][0].SetValue(False) self.rb[-1][1].SetValue(True) bs = wxBoxSizer(wxVERTICAL) bs.Add(gs, 0, wxEXPAND | wxALL, 10) bs.Add(wxStaticLine(self, -1), 0, wxEXPAND | wxTOP | wxBOTTOM, 7) but = self.CreateButtonSizer(wxOK | wxCANCEL | wxHELP) bs.Add(but, 0, wxEXPAND | wxALL, 10) self.SetSizer(bs) self.SetAutoLayout(True) bs.Fit(self) EVT_BUTTON(self, wxID_HELP, self.OnHelp) def _setting(self, index): if not self.cb[index].GetValue(): return self.NOTREQUESTED if self.rb[index][0].GetValue(): return self.MERGE return self.OVERWRITE def GetPhoneBookSetting(self): return self._setting(0) def GetCalendarSetting(self): return self._setting(1) def GetWallpaperSetting(self): return self._setting(2) def GetRingtoneSetting(self): return self._setting(3) def OnHelp(self, _): wxGetApp().displayhelpid(self.HELPID) class SendPhoneDialog(GetPhoneDialog): HELPID = helpids.ID_SEND_PHONE_DATA def __init__(self, frame, title, id = -1): GetPhoneDialog.__init__(self, frame, title, id) for i in self.cb: i.SetValue(False) self.rb[2][0].Enable(True) self.rb[3][0].Enable(True) class ConfigDialog(wxDialog): setme = '<setme>' ID_DIRBROWSE = 1 ID_COMBROWSE = 2 ID_RETRY = 3 def __init__(self, mainwindow, frame, title = 'BitPim Settings', id = -1): wxDialog.__init__(self, frame, id, title, style = wxCAPTION | wxSYSTEM_MENU | wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) self.mw = mainwindow gs = wxFlexGridSizer(2, 3, 5, 10) gs.AddGrowableCol(1) gs.Add(wxStaticText(self, -1, 'Disk storage'), 0, wxCENTER) self.diskbox = wxTextCtrl(self, -1, self.setme, size = wxSize(400, 10)) gs.Add(self.diskbox, 0, wxEXPAND) gs.Add(wxButton(self, self.ID_DIRBROWSE, 'Browse ...'), 0, wxEXPAND) gs.Add(wxStaticText(self, -1, 'Com Port'), 0, wxCENTER) self.commbox = wxTextCtrl(self, -1, self.setme) gs.Add(self.commbox, 0, wxEXPAND) gs.Add(wxButton(self, self.ID_COMBROWSE, 'Browse ...'), 0, wxEXPAND) bs = wxBoxSizer(wxVERTICAL) bs.Add(gs, 0, wxEXPAND | wxALL, 10) bs.Add(wxStaticLine(self, -1), 0, wxEXPAND | wxTOP | wxBOTTOM, 7) but = self.CreateButtonSizer(wxOK | wxCANCEL | wxHELP) bs.Add(but, 0, wxCENTER, 10) EVT_BUTTON(self, wxID_HELP, self.OnHelp) EVT_BUTTON(self, self.ID_DIRBROWSE, self.OnDirBrowse) EVT_BUTTON(self, self.ID_COMBROWSE, self.OnComBrowse) EVT_BUTTON(self, wxID_OK, self.OnOK) self.SetSizer(bs) self.SetAutoLayout(True) bs.Fit(self) def OnOK(self, _): dir = self.diskbox.GetValue() try: os.makedirs(dir) except: pass if os.path.isdir(dir): self.EndModal(wxID_OK) return None wxTipWindow(self.diskbox, 'No such directory - please correct') def OnHelp(self, _): wxGetApp().displayhelpid(helpids.ID_SETTINGS_DIALOG) def OnDirBrowse(self, _): dlg = wxDirDialog(self, defaultPath = self.diskbox.GetValue(), style = wxDD_NEW_DIR_BUTTON) res = dlg.ShowModal() v = dlg.GetPath() dlg.Destroy() if res == wxID_OK: self.diskbox.SetValue(v) def OnComBrowse(self, _): self.mw.wt.clearcomm() w = self.mw.config.ReadInt('combrowsewidth', 640) h = self.mw.config.ReadInt('combrowseheight', 480) p = self.mw.config.ReadInt('combrowsesash', 200) dlg = CommPortDialog(self, defaultport = self.commbox.GetValue(), sashposition = p) dlg.SetSize(wxSize(w, h)) dlg.Centre() res = dlg.ShowModal() v = dlg.GetPort() sz = dlg.GetSize() self.mw.config.WriteInt('combrowsewidth', sz.GetWidth()) self.mw.config.WriteInt('combrowseheight', sz.GetHeight()) self.mw.config.WriteInt('combrowsesash', dlg.sashposition) dlg.Destroy() if res == wxID_OK: self.commbox.SetValue(v) def setfromconfig(self): if len(self.mw.config.Read('path', '')): self.diskbox.SetValue(self.mw.config.Read('path', '')) if len(self.mw.config.Read('lgvx4400port')): self.commbox.SetValue(self.mw.config.Read('lgvx4400port', '')) def setdefaults(self): if self.diskbox.GetValue() == self.setme: if gui.IsMSWindows(): import _winreg x = _winreg.ConnectRegistry(None, _winreg.HKEY_CURRENT_USER) y = _winreg.OpenKey(x, 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders') str = _winreg.QueryValueEx(y, 'Personal')[0] _winreg.CloseKey(y) _winreg.CloseKey(x) path = os.path.join(str, 'bitpim') else: path = os.path.expanduser('~/.bitpim-files') self.diskbox.SetValue(path) if self.commbox.GetValue() == self.setme: comm = 'auto' self.commbox.SetValue(comm) def updatevariables(self): path = self.diskbox.GetValue() self.mw.configpath = path self.mw.ringerpath = self._fixup(os.path.join(path, 'ringer')) self.mw.wallpaperpath = self._fixup(os.path.join(path, 'wallpaper')) self.mw.phonebookpath = self._fixup(os.path.join(path, 'phonebook')) self.mw.calendarpath = self._fixup(os.path.join(path, 'calendar')) self.mw.config.Write('path', path) self.mw.commportsetting = self.commbox.GetValue() self.mw.config.Write('lgvx4400port', self.mw.commportsetting) if self.mw.wt is not None: self.mw.wt.clearcomm() commparm = { } commparm['retryontimeout'] = self.mw.config.ReadInt('commretryontimeout', False) commparm['timeout'] = self.mw.config.ReadInt('commtimeout', 3) commparm['hardwareflow'] = self.mw.config.ReadInt('commhardwareflow', False) commparm['softwareflow'] = self.mw.config.ReadInt('commsoftwareflow', False) commparm['baud'] = self.mw.config.ReadInt('commbaud', 115200) self.mw.commparams = commparm def _fixup(self, path): if len(path) >= 3: if path[1] == ':' and path[2] == '\\' and path[3] == '\\': return path[0:2] + path[3:] return path def needconfig(self): self.setfromconfig() if self.diskbox.GetValue() == self.setme or self.commbox.GetValue() == self.setme: self.setdefaults() self.updatevariables() if self.diskbox.GetValue() == self.setme or self.commbox.GetValue() == self.setme: return True try: os.makedirs(self.diskbox.GetValue()) except: pass if not os.path.isdir(self.diskbox.GetValue()): return True return False def ShowModal(self): self.setfromconfig() self.setdefaults() ec = wxDialog.ShowModal(self) if ec == wxID_OK: self.updatevariables() return ec class CommPortDialog(wxDialog): ID_LISTBOX = 1 ID_TEXTBOX = 2 ID_REFRESH = 3 ID_SASH = 4 def __init__(self, parent, id = -1, title = 'Choose a comm port', defaultport = 'auto', sashposition = 0): wxDialog.__init__(self, parent, id, title, style = wxCAPTION | wxSYSTEM_MENU | wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) self.parent = parent self.port = defaultport self.sashposition = sashposition p = self splitter = wxSplitterWindow(p, self.ID_SASH, style = wxSP_3D | wxSP_LIVE_UPDATE) self.lb = wxListBox(splitter, self.ID_LISTBOX, style = wxLB_SINGLE | wxLB_HSCROLL | wxLB_NEEDED_SB) self.tb = wxHtmlWindow(splitter, self.ID_TEXTBOX, size = wxSize(400, 400)) splitter.SplitHorizontally(self.lb, self.tb, sashposition) buttsizer = wxGridSizer(1, 4) buttsizer.Add(wxButton(p, wxID_OK, 'OK'), 0, wxALL, 10) buttsizer.Add(wxButton(p, self.ID_REFRESH, 'Refresh'), 0, wxALL, 10) buttsizer.Add(wxButton(p, wxID_HELP, 'Help'), 0, wxALL, 10) buttsizer.Add(wxButton(p, wxID_CANCEL, 'Cancel'), 0, wxALL, 10) vbs = wxBoxSizer(wxVERTICAL) vbs.Add(splitter, 1, wxEXPAND) vbs.Add(buttsizer, 0, wxCENTER) p.SetSizer(vbs) p.SetAutoLayout(True) vbs.Fit(p) self.OnRefresh() EVT_BUTTON(self, wxID_CANCEL, self.OnCancel) EVT_BUTTON(self, wxID_HELP, self.OnHelp) EVT_BUTTON(self, self.ID_REFRESH, self.OnRefresh) EVT_BUTTON(self, wxID_OK, self.OnOk) EVT_LISTBOX(self, self.ID_LISTBOX, self.OnListBox) EVT_LISTBOX_DCLICK(self, self.ID_LISTBOX, self.OnListBox) EVT_SPLITTER_SASH_POS_CHANGED(self, self.ID_SASH, self.OnSashChange) def OnSashChange(self, _ = None): self.sashposition = self.FindWindowById(self.ID_SASH).GetSashPosition() def OnRefresh(self, _ = None): self.tb.SetPage('<p><b>Refreshing</b> ...') self.lb.Clear() self.Update() ports = comscan.comscan() self.portinfo = comdiagnose.diagnose(ports) if len(self.portinfo): self.portinfo = [ ('Automatic', 'auto', '<p>BitPim will try to detect the correct port automatically when accessing your phone')] + self.portinfo self.lb.Clear() sel = -1 for name, actual, description in self.portinfo: if sel < 0 and self.GetPort() == actual: sel = self.lb.GetCount() self.lb.Append(name) if sel < 0: sel = 0 if self.lb.GetCount(): self.lb.SetSelection(sel) self.OnListBox() else: self.FindWindowById(wxID_OK).Enable(False) self.tb.SetPage('<html><body>You do not have any com/serial ports on your system</body></html>') def OnListBox(self, _ = None): p = self.portinfo[self.lb.GetSelection()] if p[1] is None: self.FindWindowById(wxID_OK).Enable(False) else: self.port = p[1] self.FindWindowById(wxID_OK).Enable(True) self.tb.SetPage(p[2]) def OnCancel(self, _): self.EndModal(wxID_CANCEL) def OnOk(self, _): self.EndModal(wxID_OK) def OnHelp(self, _): wxGetApp().displayhelpid(helpids.ID_COMMSETTINGS_DIALOG) def GetPort(self): return self.port class MyFileDropTarget(wxFileDropTarget): def __init__(self, target): wxFileDropTarget.__init__(self) self.target = target def OnDropFiles(self, x, y, filenames): return self.target.OnDropFiles(x, y, filenames) class FileView(wxListCtrl, wxListCtrlAutoWidthMixin): skiplist = ('desktop.ini', 'thumbs.db', 'zbthumbnail.info') def __init__(self, mainwindow, parent, id = -1, style = wxLC_REPORT | wxLC_SINGLE_SEL): wxListCtrl.__init__(self, parent, id, style = style) wxListCtrlAutoWidthMixin.__init__(self) self.droptarget = MyFileDropTarget(self) self.SetDropTarget(self.droptarget) self.mainwindow = mainwindow self.thedir = None self.wildcard = 'I forgot to set wildcard in derived class|*' self.maxlen = 255 if style & wxLC_REPORT == wxLC_REPORT or gui.HasFullyFunctionalListView(): self.InsertColumn(0, 'Name') self.InsertColumn(1, 'Bytes', wxLIST_FORMAT_RIGHT) self.SetColumnWidth(0, 200) self.menu = wxMenu() self.menu.Append(gui.ID_FV_OPEN, 'Open') self.menu.AppendSeparator() self.menu.Append(gui.ID_FV_DELETE, 'Delete') self.menu.AppendSeparator() self.menu.Append(gui.ID_FV_RENAME, 'Rename') self.menu.Append(gui.ID_FV_REFRESH, 'Refresh') self.menu.Append(gui.ID_FV_PROPERTIES, 'Properties') self.addfilemenu = wxMenu() self.addfilemenu.Append(gui.ID_FV_ADD, 'Add ...') self.addfilemenu.Append(gui.ID_FV_REFRESH, 'Refresh') EVT_MENU(self.menu, gui.ID_FV_REFRESH, self.OnRefresh) EVT_MENU(self.addfilemenu, gui.ID_FV_REFRESH, self.OnRefresh) EVT_MENU(self.addfilemenu, gui.ID_FV_ADD, self.OnAdd) EVT_MENU(self.menu, gui.ID_FV_OPEN, self.OnLaunch) EVT_MENU(self.menu, gui.ID_FV_DELETE, self.OnDelete) EVT_MENU(self.menu, gui.ID_FV_PROPERTIES, self.OnProperties) EVT_LEFT_DCLICK(self, self.OnLaunch) EVT_LIST_ITEM_SELECTED(self, -1, self.OnItemActivated) EVT_RIGHT_DOWN(self, self.OnRightDown) EVT_COMMAND_RIGHT_CLICK(self, id, self.OnRightClick) EVT_RIGHT_UP(self, self.OnRightClick) EVT_KEY_DOWN(self, self.OnKeyDown) def OnRightDown(self, event): (item, flags) = self.HitTest(wxPoint(event.GetX(), event.GetY())) if flags & wxLIST_HITTEST_ONITEM: self.selecteditem = item self.SetItemState(item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED) else: self.selecteditem = -1 def OnRightClick(self, event): if self.selecteditem >= 0: self.PopupMenu(self.menu, event.GetPosition()) else: self.PopupMenu(self.addfilemenu, event.GetPosition()) def OnKeyDown(self, event): if event.GetKeyCode() == WXK_DELETE: self.OnDelete(event) return None event.Skip() def OnItemActivated(self, event): self.selecteditem = event.m_itemIndex def OnLaunch(self, _ = None): name = self.GetItemText(self.selecteditem) ext = name[name.rfind('.') + 1:] type = wxTheMimeTypesManager.GetFileTypeFromExtension(ext) cmd = type.GetOpenCommand(os.path.join(self.thedir, name)) if cmd is None or len(cmd) == 0: dlg = AlertDialogWithHelp(self, "You don't have any programs defined to open ." + ext + ' files', 'Unable to open', (lambda _: wxGetApp().displayhelpid(helpids.ID_NO_MIME_OPEN)), style = wxOK | wxICON_INFORMATION) dlg.ShowModal() dlg.Destroy() else: try: wxExecute(cmd) except: dlg = AlertDialogWithHelp(self, "Unable to execute '" + cmd + "'", 'Open failed', (lambda _: wxGetApp().displayhelpid(helpids.ID_MIME_EXEC_FAILED)), style = wxOK | wxICON_ERROR) dlg.ShowModal() dlg.Destroy() def OnDropFiles(self, _, dummy, filenames): target = self t = self.mainwindow.nb.GetPage(self.mainwindow.nb.GetSelection()) if isinstance(t, FileView): target = t for f in filenames: target.OnAddFile(f) def OnAdd(self, _ = None): dlg = wxFileDialog(self, 'Choose files', style = wxOPEN | wxMULTIPLE, wildcard = self.wildcard) if dlg.ShowModal() == wxID_OK: for file in dlg.GetPaths(): self.OnAddFile(file) dlg.Destroy() def OnAddFile(self, _): raise Exception('not implemented') def OnRefresh(self, _ = None): result = { } self.getfromfs(result) self.populate(result) def OnDelete(self, _): name = self.GetItemText(self.selecteditem) os.remove(os.path.join(self.thedir, name)) self.OnRefresh() def versionupgrade(self, dict, version): raise Exception('not implemented') def OnProperties(self, _): raise Exception('not implemented') def getfromfs(self, _): raise Exception('not implemented') def populate(self, _): raise Exception('not implemented') def seticonview(self): self.SetSingleStyle(wxLC_REPORT, False) self.SetSingleStyle(wxLC_ICON, True) def setlistview(self): self.SetSingleStyle(wxLC_ICON, False) self.SetSingleStyle(wxLC_REPORT, True) def genericpopulatefs(self, dict, key, indexkey, version): try: os.makedirs(self.thedir) except: pass if not os.path.isdir(self.thedir): raise Exception('Bad directory for ' + key + " '" + self.thedir + "'") for f in os.listdir(self.thedir): if f.lower() not in self.skiplist: os.remove(os.path.join(self.thedir, f)) continue d = dict[key] for i in d: f = open(os.path.join(self.thedir, i), 'wb') f.write(d[i]) f.close() d = { } d[indexkey] = dict[indexkey] common.writeversionindexfile(os.path.join(self.thedir, 'index.idx'), d, version) return dict def genericgetfromfs(self, result, key, indexkey, currentversion): try: os.makedirs(self.thedir) except: pass if not os.path.isdir(self.thedir): raise Exception('Bad directory for ' + key + " '" + self.thedir + "'") dict = { } for file in os.listdir(self.thedir): if file == 'index.idx': d = { } d['result'] = { } common.readversionedindexfile(os.path.join(self.thedir, file), d, self.versionupgrade, currentversion) result.update(d['result']) continue if file.lower() in self.skiplist: continue continue f = open(os.path.join(self.thedir, file), 'rb') data = f.read() f.close() dict[file] = data result[key] = dict if indexkey not in result: result[indexkey] = { } return result def getshortenedbasename(self, filename, newext = ''): filename = basename(filename).lower() if len(newext): filename = stripext(filename) + '.' + newext if len(filename) > self.maxlen: chop = len(filename) - self.maxlen filename = stripext(filename)[:-chop] + '.' + getext(filename) return os.path.join(self.thedir, filename) class RingerView(FileView): CURRENTFILEVERSION = 1 def __init__(self, mainwindow, parent, id = -1): FileView.__init__(self, mainwindow, parent, id) self.InsertColumn(2, 'Length') self.InsertColumn(3, 'Index') self.InsertColumn(4, 'Description') il = wxImageList(32, 32) il.Add(gui.getbitmap('ringer')) self.AssignImageList(il, wxIMAGE_LIST_NORMAL) self._data = { } self._data['ringtone'] = { } self._data['ringtone-index'] = { } self.wildcard = 'MIDI files (*.mid)|*.mid' self.maxlen = 19 def getdata(self, dict): dict.update(self._data) return dict def OnAddFile(self, file): self.thedir = self.mainwindow.ringerpath target = self.getshortenedbasename(file, 'mid') if target == None: return None f = open(file, 'rb') contents = f.read() f.close() if len(contents) >= 65534: raise Exception(file + ' is too big at ' + `len(contents)` + ' bytes. Max size is 64k') f = open(target, 'wb') f.write(contents) f.close() self.OnRefresh() def populatefs(self, dict): self.thedir = self.mainwindow.ringerpath return self.genericpopulatefs(dict, 'ringtone', 'ringtone-index', self.CURRENTFILEVERSION) def populate(self, dict): self.DeleteAllItems() self._data = { } self._data['ringtone'] = dict['ringtone'].copy() self._data['ringtone-index'] = dict['ringtone-index'].copy() count = 0 keys = dict['ringtone'].keys() keys.sort() for i in keys: item = { } item['name'] = i item['data'] = dict['ringtone'][i] item['index'] = -1 for ii in dict['ringtone-index']: if dict['ringtone-index'][ii] == i: item['index'] = ii break continue self.InsertImageStringItem(count, item['name'], 0) self.SetStringItem(count, 0, item['name']) self.SetStringItem(count, 1, `len(item['data'])`) self.SetStringItem(count, 2, '1 second :-)') self.SetStringItem(count, 3, `item['index']`) self.SetStringItem(count, 4, 'Midi file') count += 1 def getfromfs(self, result): self.thedir = self.mainwindow.ringerpath return self.genericgetfromfs(result, 'ringtone', 'ringtone-index', self.CURRENTFILEVERSION) def versionupgrade(self, dict, version): if version == 0: version = 1 class WallpaperView(FileView): CURRENTFILEVERSION = 1 ID_DELETEFILE = 2 ID_IGNOREFILE = 3 def __init__(self, mainwindow, parent, id = -1): FileView.__init__(self, mainwindow, parent, id, style = wxLC_ICON | wxLC_SINGLE_SEL) if gui.HasFullyFunctionalListView(): self.InsertColumn(2, 'Size') self.InsertColumn(3, 'Index') self._data = { } self._data['wallpaper'] = { } self._data['wallpaper-index'] = { } self.maxlen = 19 self.wildcard = 'Image files|*.bmp;*.jpg;*.jpeg;*.png;*.gif;*.pnm;*.tiff;*.ico;*.bci' self.usewidth = 120 self.useheight = 98 self.addfilemenu.Insert(1, gui.ID_FV_PASTE, 'Paste') EVT_MENU(self.addfilemenu, gui.ID_FV_PASTE, self.OnPaste) def isBCI(self, filename): f = open(filename, 'rb') four = f.read(4) f.close() if four == 'BCI\x00': return True return False def getdata(self, dict): dict.update(self._data) return dict def populate(self, dict): self.DeleteAllItems() self._data = { } self._data['wallpaper'] = dict['wallpaper'].copy() self._data['wallpaper-index'] = dict['wallpaper-index'].copy() il = wxImageList(self.usewidth, self.useheight) self.AssignImageList(il, wxIMAGE_LIST_NORMAL) count = 0 keys = dict['wallpaper'].keys() keys.sort() for i in keys: file = os.path.join(self.mainwindow.wallpaperpath, i) if self.isBCI(file): image = brewcompressedimage.getimage(file) else: image = wxImage(file) if not image.Ok(): dlg = AnotherDialog(self, 'This is not a valid image file:\n\n' + file, 'Invalid Image file', (('Delete', self.ID_DELETEFILE), ('Ignore', self.ID_IGNOREFILE), ('Help', wxID_HELP)), (lambda _: wxGetApp().displayhelpid(helpids.ID_INVALID_FILE_MESSAGE))) x = dlg.ShowModal() dlg.Destroy() print 'result is', x if x == self.ID_DELETEFILE: os.remove(file) continue continue width = min(image.GetWidth(), self.usewidth) height = min(image.GetHeight(), self.useheight) img = image.GetSubImage(wxRect(0, 0, width, height)) if width != self.usewidth or height != self.useheight: b = wxEmptyBitmap(self.usewidth, self.useheight) mdc = wxMemoryDC() mdc.SelectObject(b) mdc.Clear() mdc.DrawBitmap(img.ConvertToBitmap(), 0, 0, True) mdc.SelectObject(wxNullBitmap) bitmap = b else: bitmap = img.ConvertToBitmap() pos = -1 try: pos = il.Add(bitmap) except: pass if pos < 0: dlg = wxMessageDialog(self, "Failed to add to imagelist image in '" + file + "'", 'Imagelist got upset', style = wxOK | wxICON_ERROR) dlg.ShowModal() il.Add(wxNullBitmap) item = { } item['name'] = i item['data'] = dict['wallpaper'][i] item['index'] = -1 for ii in dict['wallpaper-index']: if dict['wallpaper-index'][ii] == i: item['index'] = ii break continue self.InsertImageStringItem(count, item['name'], count) if gui.HasFullyFunctionalListView(): self.SetStringItem(count, 0, item['name']) self.SetStringItem(count, 1, `len(item['data'])`) self.SetStringItem(count, 2, '%d x %d' % (image.GetWidth(), image.GetHeight())) self.SetStringItem(count, 3, `item['index']`) image.Destroy() count += 1 def OnPaste(self, _ = None): do = wxBitmapDataObject() wxTheClipboard.Open() success = wxTheClipboard.GetData(do) wxTheClipboard.Close() if not success: wxMessageBox("There isn't an image in the clipboard", 'Error') return None self.thedir = self.mainwindow.wallpaperpath for i in range(255): name = 'clipboard' + `i` + '.bmp' if not os.path.exists(os.path.join(self.thedir, name)): break continue self.OnAddImage(wxImageFromBitmap(do.GetBitmap()), name) def OnAddFile(self, file): self.thedir = self.mainwindow.wallpaperpath if self.isBCI(file): target = os.path.join(self.thedir, os.path.basename(file)) src = open(file, 'rb') dest = open(target, 'wb') dest.write(src.read()) dest.close() src.close() self.OnRefresh() return None img = wxImage(file) if not img.Ok(): dlg = wxMessageDialog(self, "Failed to understand the image in '" + file + "'", 'Image not understood', style = wxOK | wxICON_ERROR) dlg.ShowModal() return None self.OnAddImage(img, file) def OnAddImage(self, img, file): target = self.getshortenedbasename(file, 'bmp') if target == None: return None obj = img if img.GetWidth() > self.usewidth * 120 / 100 and img.GetHeight() > self.useheight * 120 / 100 and img.GetWidth() < self.usewidth * 60 / 100 or img.GetHeight() < self.useheight * 60 / 100: bitmap = wxEmptyBitmap(self.usewidth, self.useheight) mdc = wxMemoryDC() mdc.SelectObject(bitmap) sfactorw = self.usewidth * 10000 / img.GetWidth() sfactorh = self.useheight * 10000 / img.GetHeight() sfactor = min(sfactorw, sfactorh) newwidth = img.GetWidth() * sfactor / 10000 newheight = img.GetHeight() * sfactor / 10000 self.mainwindow.OnLog('Resizing %s from %dx%d to %dx%d' % (target, img.GetWidth(), img.GetHeight(), newwidth, newheight)) img.Rescale(newwidth, newheight) posx = self.usewidth - (self.usewidth + newwidth) / 2 posy = self.useheight - (self.useheight + newheight) / 2 mdc.Clear() mdc.DrawBitmap(img.ConvertToBitmap(), posx, posy, True) obj = bitmap if not obj.SaveFile(target, wxBITMAP_TYPE_BMP): os.remove(target) dlg = wxMessageDialog(self, "Failed to convert the image in '" + file + "'", 'Image not converted', style = wxOK | wxICON_ERROR) dlg.ShowModal() return None self.OnRefresh() def populatefs(self, dict): self.thedir = self.mainwindow.wallpaperpath return self.genericpopulatefs(dict, 'wallpaper', 'wallpaper-index', self.CURRENTFILEVERSION) def getfromfs(self, result): self.thedir = self.mainwindow.wallpaperpath return self.genericgetfromfs(result, 'wallpaper', 'wallpaper-index', self.CURRENTFILEVERSION) def versionupgrade(self, dict, version): if version == 0: version = 1 def basename(name): if name.rfind('\\') >= 0 or name.rfind('/') >= 0: pos = max(name.rfind('\\'), name.rfind('/')) name = name[pos + 1:] return name def stripext(name): if name.rfind('.') >= 0: name = name[:name.rfind('.')] return name def getext(name): if name.rfind('.') >= 0: return name[name.rfind('.') + 1:] return '' class Calendar(calendarcontrol.Calendar): CURRENTFILEVERSION = 2 def __init__(self, mainwindow, parent, id = -1): self.mainwindow = mainwindow self.entrycache = { } self.entries = { } self.repeating = [] self._data = { } calendarcontrol.Calendar.__init__(self, parent, rows = 5, id = id) self.dialog = DayViewDialog(self, self) self._nextpos = -1 def getdata(self, dict): dict['calendar'] = self._data return dict def updateonchange(self): d = { } d = self.getdata(d) self.populatefs(d) self.populate(d) self.RefreshAllEntries() def AddEntry(self, entry): self._data[entry['pos']] = entry self.updateonchange() def DeleteEntry(self, entry): del self._data[entry['pos']] self.updateonchange() def DeleteEntryRepeat(self, entry, year, month, day): e = self._data[entry['pos']] if not e.has_key('exceptions'): e['exceptions'] = [] e['exceptions'].append((year, month, day)) self.updateonchange() def ChangeEntry(self, oldentry, newentry): self._data[newentry['pos']] = newentry self.updateonchange() def getentrydata(self, year, month, day): res = self.entrycache.get((year, month, day), None) if res is not None: return res dayofweek = calendar.weekday(year, month, day) dayofweek = (dayofweek + 1) % 7 res = [] fixed = self.entries.get((year, month, day), []) res.extend(fixed) repeats = [] for i in self.repeating: (y, m, d) = i['start'][0:3] if not year < y: if year <= y and month < m and year <= y and month <= m and day < d: continue (y, m, d) = i['end'][0:3] if not year > y: if year == y and month > m and year == y and month == m and day > d: continue if (year, month, day) in i.get('exceptions', ()): continue repeating = i['repeat'] if repeating == 'daily': repeats.append(i) continue if repeating == 'monfri': if dayofweek > 0 and dayofweek < 6: repeats.append(i) continue continue if repeating == 'weekly': if i['dayofweek'] == dayofweek: repeats.append(i) continue continue if repeating == 'monthly': if day == i['start'][2]: repeats.append(i) continue continue if repeating == 'yearly': if day == i['start'][2] and month == i['start'][1]: repeats.append(i) continue continue continue res.extend(repeats) self.entrycache[(year, month, day)] = res return res def newentryfactory(self, year, month, day): res = { } now = time.localtime() res['start'] = (year, month, day, now.tm_hour, now.tm_min) res['end'] = [ year, month, day, now.tm_hour, now.tm_min] if res['end'][3] < 23: res['end'][3] += 1 res['end'][4] = 0 else: res['end'][3] = 23 res['end'][4] = 59 res['repeat'] = None res['description'] = 'New event' res['changeserial'] = 1 res['snoozedelay'] = 0 res['alarm'] = None res['daybitmap'] = 0 res['ringtone'] = 0 res['pos'] = self.allocnextpos() return res def getdaybitmap(self, start, repeat): if repeat != 'weekly': return 0 dayofweek = calendar.weekday(*start[:3]) dayofweek = (dayofweek + 1) % 7 return [ 2048, 1024, 512, 256, 128, 64, 32][dayofweek] def allocnextpos(self): while True: (self._nextpos, res) = (self._nextpos - 1, self._nextpos) if res not in self._data: return res continue return -1 def OnGetEntries(self, year, month, day): res = [ (i['start'][3], i['start'][4], i['description']) for i in self.getentrydata(year, month, day) ] res.sort() return res def OnEdit(self, year, month, day): if self.dialog.dirty: wxBell() else: self.dialog.setdate(year, month, day) self.dialog.Show(True) def populate(self, dict): self._data = dict['calendar'] self.entrycache = { } self.entries = { } self.repeating = [] for entry in self._data: entry = self._data[entry] (y, m, d, h, min) = entry['start'] if entry['repeat'] is None: if not self.entries.has_key((y, m, d)): self.entries[(y, m, d)] = [] self.entries[(y, m, d)].append(entry) continue if entry['repeat'] == 'weekly': entry['dayofweek'] = (calendar.weekday(y, m, d) + 1) % 7 self.repeating.append(entry) self.RefreshAllEntries() def populatefs(self, dict): self.thedir = self.mainwindow.calendarpath try: os.makedirs(self.thedir) except: pass if not os.path.isdir(self.thedir): raise Exception("Bad directory for calendar '" + self.thedir + "'") for f in os.listdir(self.thedir): os.remove(os.path.join(self.thedir, f)) d = { } d['calendar'] = dict['calendar'] common.writeversionindexfile(os.path.join(self.thedir, 'index.idx'), d, self.CURRENTFILEVERSION) return dict def getfromfs(self, dict): self.thedir = self.mainwindow.calendarpath try: os.makedirs(self.thedir) except: pass if not os.path.isdir(self.thedir): raise Exception("Bad directory for calendar '" + self.thedir + "'") if os.path.exists(os.path.join(self.thedir, 'index.idx')): d = { 'result': { } } common.readversionedindexfile(os.path.join(self.thedir, 'index.idx'), d, self.versionupgrade, self.CURRENTFILEVERSION) dict.update(d['result']) else: dict['calendar'] = { } return dict def versionupgrade(self, dict, version): if version == 0: version = 1 if version == 1: version = 2 for k in dict['result']['calendar']: entry = dict['result']['calendar'][k] entry['daybitmap'] = self.getdaybitmap(entry['start'], entry['repeat']) del entry['?d'] class DayViewDialog(wxDialog): ID_PREV = 1 ID_NEXT = 2 ID_ADD = 3 ID_DELETE = 4 ID_CLOSE = 5 ID_LISTBOX = 6 ID_START = 7 ID_END = 8 ID_REPEAT = 9 ID_DESCRIPTION = 10 ID_SAVE = 11 ID_HELP = 12 ID_REVERT = 13 ANSWER_ORIGINAL = 1 ANSWER_THIS = 2 ANSWER_CANCEL = 3 def __init__(self, parent, calendarwidget, id = -1, title = 'Edit Calendar'): self.cw = calendarwidget wxDialog.__init__(self, parent, id, title, style = wxDEFAULT_DIALOG_STYLE) vbs = wxBoxSizer(wxVERTICAL) prev = wxButton(self, self.ID_PREV, '<', style = wxBU_EXACTFIT) next = wxButton(self, self.ID_NEXT, '>', style = wxBU_EXACTFIT) self.title = wxStaticText(self, -1, 'Date here', style = wxALIGN_CENTRE | wxST_NO_AUTORESIZE) hbs1 = wxBoxSizer(wxHORIZONTAL) hbs1.Add(prev, 0, wxEXPAND) hbs1.Add(self.title, 1, wxEXPAND) hbs1.Add(next, 0, wxEXPAND) vbs.Add(hbs1, 0, wxEXPAND) self.listbox = wxListBox(self, self.ID_LISTBOX, style = wxLB_SINGLE | wxLB_HSCROLL | wxLB_NEEDED_SB) add = wxButton(self, self.ID_ADD, 'New') hbs2 = wxBoxSizer(wxHORIZONTAL) hbs2.Add(add, 1, wxALIGN_CENTER | wxLEFT | wxRIGHT, border = 5) lbs = wxBoxSizer(wxVERTICAL) lbs.Add(self.listbox, 1, wxEXPAND | wxBOTTOM, border = 5) lbs.Add(hbs2, 0, wxEXPAND) self.fieldnames = ('description', 'start', 'end', 'repeat', 'alarm', 'ringtone', 'changeserial', 'snoozedelay') self.fielddesc = ('Description', 'Start', 'End', 'Repeat', 'Alarm', 'Ringtone', 'changeserial', 'Snooze Delay') gs = wxFlexGridSizer(-1, 2, 5, 5) gs.AddGrowableCol(1) self.fields = { } for desc, field in zip(self.fielddesc, self.fieldnames): t = wxStaticText(self, -1, desc, style = wxALIGN_LEFT) gs.Add(t) if field == 'start': c = DVDateTimeControl(self, self.ID_START) elif field == 'end': c = DVDateTimeControl(self, self.ID_END) elif field == 'repeat': c = DVRepeatControl(self, self.ID_REPEAT) elif field == 'description': c = DVTextControl(self, self.ID_DESCRIPTION, 'dummy') else: print 'field', field, 'needs an id' c = DVIntControl(self, -1) gs.Add(c, 0, wxEXPAND) self.fields[field] = c delete = wxButton(self, self.ID_DELETE, 'Delete') revert = wxButton(self, self.ID_REVERT, 'Revert') save = wxButton(self, self.ID_SAVE, 'Save') hbs4 = wxBoxSizer(wxHORIZONTAL) hbs4.Add(delete, 1, wxALIGN_CENTRE | wxLEFT, border = 10) hbs4.Add(revert, 1, wxALIGN_CENTRE | wxLEFT | wxRIGHT, border = 10) hbs4.Add(save, 1, wxALIGN_CENTRE | wxRIGHT, border = 10) vbs2 = wxBoxSizer(wxVERTICAL) vbs2.Add(gs, 1, wxEXPAND | wxBOTTOM, border = 5) vbs2.Add(hbs4, 0, wxEXPAND | wxALIGN_CENTRE) hbs3 = wxBoxSizer(wxHORIZONTAL) hbs3.Add(lbs, 1, wxEXPAND | wxALL, 5) hbs3.Add(vbs2, 2, wxEXPAND | wxALL, 5) vbs.Add(hbs3, 1, wxEXPAND) vbs.Add(wxStaticLine(self, -1, style = wxLI_HORIZONTAL), 0, wxEXPAND) help = wxButton(self, self.ID_HELP, 'Help') close = wxButton(self, self.ID_CLOSE, 'Close') hbs4 = wxBoxSizer(wxHORIZONTAL) hbs4.Add(help, 0, wxALL, 5) hbs4.Add(close, 0, wxALL, 5) vbs.Add(hbs4, 0, wxALIGN_RIGHT | wxALL, 5) self.SetSizer(vbs) self.SetAutoLayout(True) vbs.Fit(self) self.FindWindowById(self.ID_DELETE).Enable(False) EVT_LISTBOX(self, self.ID_LISTBOX, self.OnListBoxItem) EVT_LISTBOX_DCLICK(self, self.ID_LISTBOX, self.OnListBoxItem) EVT_BUTTON(self, self.ID_SAVE, self.OnSaveButton) EVT_BUTTON(self, self.ID_REVERT, self.OnRevertButton) EVT_BUTTON(self, self.ID_CLOSE, self.OnCloseButton) EVT_BUTTON(self, self.ID_ADD, self.OnNewButton) EVT_BUTTON(self, self.ID_DELETE, self.OnDeleteButton) EVT_BUTTON(self, self.ID_HELP, (lambda _: wxGetApp().displayhelpid(helpids.ID_EDITING_CALENDAR_EVENTS))) EVT_BUTTON(self, self.ID_PREV, self.OnPrevDayButton) EVT_BUTTON(self, self.ID_NEXT, self.OnNextDayButton) EVT_CLOSE(self, self.OnCloseWindow) self.entries = [] self.entrymap = [] self.dirty = None self.ignoredirty = False self.setdirty(False) def AskAboutRepeatDelete(self): return self._AskAboutRecurringEvent('Delete recurring event?', 'Do you want to delete all the recurring events, or just this one?', 'Delete') def AskAboutRepeatChange(self): return self._AskAboutRecurringEvent('Change recurring event?', 'Do you want to change all the recurring events, or just this one?', 'Change') def _AskAboutRecurringEvent(self, caption, text, prefix): dlg = RecurringDialog(self, caption, text, prefix) res = dlg.ShowModal() dlg.Destroy() if res == dlg.ID_THIS: return self.ANSWER_THIS if res == dlg.ID_ALL: return self.ANSWER_ORIGINAL if res == dlg.ID_CANCEL: return self.ANSWER_CANCEL def OnListBoxItem(self, _ = None): self.updatefields(self.getcurrententry()) self.setdirty(False) self.FindWindowById(self.ID_DELETE).Enable(True) def getcurrententry(self): return self.getentry(self.listbox.GetSelection()) def getentry(self, num): return self.entries[self.entrymap[num]] def OnSaveButton(self, _ = None): for x in ('start', 'end'): if not self.fields[x].IsValid(): self.fields[x].SetFocus() wxBell() return None continue start = self.fields['start'].GetValue() end = self.fields['end'].GetValue() if not end[0] < start[0]: if not end[0] == start[0] and end[1] < start[1]: if not end[0] == start[0] and end[1] == start[1] and end[2] < start[2]: if end[0] == start[0] and end[1] == start[1] and end[2] == start[2] and end[3] < start[3] and end[0] == start[0] and end[1] == start[1] and end[2] == start[2] and end[3] == start[3] and end[4] < start[4]: dlg = wxMessageDialog(self, 'End date and time is before start!', 'Time Travel Attempt Detected', wxOK | wxICON_EXCLAMATION) dlg.ShowModal() dlg.Destroy() self.fields['end'].SetFocus() return None entry = self.getcurrententry() res = self.ANSWER_ORIGINAL if entry['repeat'] is not None: res = self.AskAboutRepeatChange() if res == self.ANSWER_CANCEL: return None if res == self.ANSWER_ORIGINAL: newentry = copy.copy(entry) newentry['changeserial'] = entry['changeserial'] + 1 else: newentry = self.cw.newentryfactory(*self.date) for f in self.fields: control = self.fields[f] if isinstance(control, DVDateTimeControl): if res == self.ANSWER_ORIGINAL: d = control.GetValue()[0:3] else: d = self.date v = list(d) + list(control.GetValue())[3:] else: v = control.GetValue() if f == 'repeat' and res == self.ANSWER_THIS: v = None newentry[f] = v newentry['daybitmap'] = self.cw.getdaybitmap(newentry['start'], newentry['repeat']) if res == self.ANSWER_ORIGINAL: self.cw.ChangeEntry(entry, newentry) else: self.cw.DeleteEntryRepeat(entry, *self.date) self.cw.AddEntry(newentry) self.setdirty(False) date = tuple(newentry['start'][:3]) if tuple(self.date) != date: self.cw.showday(*date) self.cw.setselection(*date) self.setdate(*date) else: self.refreshentries() self.updatelistbox(newentry['pos']) def OnPrevDayButton(self, _): (y, m, d) = self.date (y, m, d) = calendarcontrol.normalizedate(y, m, d - 1) self.setdate(y, m, d) self.cw.setday(y, m, d) def OnNextDayButton(self, _): (y, m, d) = self.date (y, m, d) = calendarcontrol.normalizedate(y, m, d + 1) self.setdate(y, m, d) self.cw.setday(y, m, d) def OnNewButton(self, _ = None): entry = self.cw.newentryfactory(*self.date) self.cw.AddEntry(entry) self.refreshentries() self.updatelistbox(entry['pos']) def OnRevertButton(self, _ = None): self.OnListBoxItem() def OnDeleteButton(self, _ = None): entry = self.getcurrententry() res = self.ANSWER_ORIGINAL if entry['repeat'] is not None: res = self.AskAboutRepeatDelete() if res == self.ANSWER_CANCEL: return None enum = self.listbox.GetSelection() if enum + 1 < len(self.entrymap): newpos = self.getentry(enum + 1)['pos'] elif enum - 1 >= 0: newpos = self.getentry(enum - 1)['pos'] else: newpos = None if res == self.ANSWER_ORIGINAL: self.cw.DeleteEntry(entry) else: self.cw.DeleteEntryRepeat(entry, *self.date) self.refreshentries() self.updatelistbox(newpos) def OnCloseWindow(self, event): if self.FindWindowById(self.ID_CLOSE).IsEnabled(): self.Show(False) elif event.CanVeto(): event.Veto() wxBell() def OnCloseButton(self, _ = None): self.Show(False) def setdate(self, year, month, day): d = time.strftime('%A %d %B %Y', (year, month, day, 0, 0, 0, calendar.weekday(year, month, day), 1, 0)) self.date = (year, month, day) self.title.SetLabel(d) self.refreshentries() self.updatelistbox() self.updatefields(None) def refreshentries(self): self.entries = self.cw.getentrydata(*self.date) def updatelistbox(self, entrytoselect = None): self.listbox.Clear() selectitem = -1 self.entrymap = [] for index, entry in zip(range(len(self.entries)), self.entries): e = (entry['start'][3:5], entry['end'][3:5], entry['description'], entry['pos'], index) self.entrymap.append(e) self.entrymap.sort() self.entrymap = [ index for ign0, ign1, ign2, ign3, index in self.entrymap ] for curpos, index in zip(range(len(self.entrymap)), self.entrymap): e = self.entries[index] hr = e['start'][3] ap = 'am' if hr >= 12: ap = 'pm' hr -= 12 if hr == 0: hr = 12 str = '%2d:%02d %s' % (hr, e['start'][4], ap) str += ' ' + e['description'] self.listbox.Append(str) if selectitem >= 0: self.listbox.SetSelection(selectitem) self.OnListBoxItem() else: self.updatefields(None) if len(self.entries) == 0: self.FindWindowById(self.ID_DELETE).Enable(False) def updatefields(self, entry): self.ignoredirty = True active = True if entry is None: for i in self.fields: self.fields[i].SetValue(None) active = False else: for i in self.fieldnames: self.fields[i].SetValue(entry[i]) for i in self.fields: self.fields[i].Enable(active) self.ignoredirty = False def OnMakeDirty(self, _ = None): self.setdirty(True) def setdirty(self, val): if self.ignoredirty: return None self.dirty = val if self.dirty: self.FindWindowById(self.ID_SAVE).Enable(True) self.FindWindowById(self.ID_REVERT).Enable(True) self.FindWindowById(self.ID_DELETE).Enable(True) self.FindWindowById(self.ID_CLOSE).Enable(False) self.FindWindowById(self.ID_PREV).Enable(False) self.FindWindowById(self.ID_NEXT).Enable(False) self.FindWindowById(self.ID_ADD).Enable(False) self.FindWindowById(self.ID_LISTBOX).Enable(False) else: self.FindWindowById(self.ID_SAVE).Enable(False) self.FindWindowById(self.ID_REVERT).Enable(False) self.FindWindowById(self.ID_CLOSE).Enable(True) self.FindWindowById(self.ID_DELETE).Enable(len(self.entries) > 0) self.FindWindowById(self.ID_PREV).Enable(True) self.FindWindowById(self.ID_NEXT).Enable(True) self.FindWindowById(self.ID_ADD).Enable(True) self.FindWindowById(self.ID_LISTBOX).Enable(True) class DVDateTimeControl(wxPanel): def __init__(self, parent, id): f = 'EUDATETIMEYYYYMMDD.HHMM' wxPanel.__init__(self, parent, -1) self.c = wxMaskedTextCtrl(self, id, '', autoformat = f) bs = wxBoxSizer(wxHORIZONTAL) bs.Add(self.c, 0, wxEXPAND) self.SetSizer(bs) self.SetAutoLayout(True) bs.Fit(self) EVT_TEXT(self.c, id, parent.OnMakeDirty) def SetValue(self, v): if v is None: self.c.SetValue('') return None ap = 'A' v = list(v) if v[3] > 12: v[3] -= 12 ap = 'P' elif v[3] == 0: v[3] = 12 elif v[3] == 12: ap = 'P' v = v + [ ap] str = '%04d%02d%02d%02d%02d%s' % tuple(v) self.c.SetValue(str) self.c.Refresh() def GetValue(self): str = self.c.GetValue() digits = '0123456789' res = [] val = None for i in str: if i in digits: if val is None: val = 0 val *= 10 val += int(i) continue if val is not None: res.append(val) val = None continue if str[-2] == 'P' or str[-2] == 'p': if res[3] != 12: res[3] += 12 elif res[3] == 12: res[3] = 0 return res def IsValid(self): return self.c.IsValid() class DVRepeatControl(wxChoice): vals = [ None, 'daily', 'monfri', 'weekly', 'monthly', 'yearly'] desc = [ 'None', 'Daily', 'Mon - Fri', 'Weekly', 'Monthly', 'Yearly'] def __init__(self, parent, id): wxChoice.__init__(self, parent, id, choices = self.desc) EVT_CHOICE(self, id, parent.OnMakeDirty) def SetValue(self, v): self.SetSelection(self.vals.index(v)) def GetValue(self): s = self.GetSelection() if s < 0: s = 0 return self.vals[s] class DVIntControl(wxIntCtrl): def __init__(self, parent, id): wxIntCtrl.__init__(self, parent, id, limited = True) EVT_INT(self, id, parent.OnMakeDirty) def SetValue(self, v): if v is None: v = -1 wxIntCtrl.SetValue(self, v) class DVTextControl(wxTextCtrl): def __init__(self, parent, id, value = ''): if value is None: value = '' wxTextCtrl.__init__(self, parent, id, value) EVT_TEXT(self, id, parent.OnMakeDirty) def SetValue(self, v): if v is None: v = '' wxTextCtrl.SetValue(self, v) class RecurringDialog(wxDialog): ID_THIS = 1 ID_ALL = 2 ID_CANCEL = 3 ID_HELP = 4 def __init__(self, parent, caption, text, prefix): wxDialog.__init__(self, parent, -1, caption, style = wxCAPTION) vbs = wxBoxSizer(wxVERTICAL) t = wxStaticText(self, -1, text) vbs.Add(t, 1, wxEXPAND | wxALL, 10) vbs.Add(wxStaticLine(self, -1), 0, wxEXPAND | wxTOP | wxBOTTOM, 3) buttonsizer = wxBoxSizer(wxHORIZONTAL) for id, label in ((self.ID_THIS, '%s %s' % (prefix, 'this')), (self.ID_ALL, '%s %s' % (prefix, 'all')), (self.ID_CANCEL, 'Cancel'), (self.ID_HELP, 'Help')): b = wxButton(self, id, label) EVT_BUTTON(self, id, self._onbutton) buttonsizer.Add(b, 5, wxALIGN_CENTER | wxALL, 5) vbs.Add(buttonsizer, 0, wxEXPAND | wxALL, 2) self.SetSizer(vbs) self.SetAutoLayout(True) vbs.Fit(self) def _onbutton(self, evt): if evt.GetId() == self.ID_HELP: pass else: self.EndModal(evt.GetId()) class MyFixedScrolledMessageDialog(wxDialog): def __init__(self, parent, msg, caption, helpid, pos = wxDefaultPosition, size = (850, 600)): wxDialog.__init__(self, parent, -1, caption, pos, size) text = wxTextCtrl(self, 1, style = wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2 | wxNO_FULL_REPAINT_ON_RESIZE | wxTE_DONTWRAP) f = wxFont(10, wxMODERN, wxNORMAL, wxNORMAL) ta = wxTextAttr(font = f) text.SetDefaultStyle(ta) text.AppendText(msg) text.SetInsertionPoint(0) text.ShowPosition(text.XYToPosition(0, 0)) vbs = wxBoxSizer(wxVERTICAL) vbs.Add(text, 1, wxEXPAND | wxALL, 10) vbs.Add(self.CreateButtonSizer(wxOK | wxHELP), 0, wxALIGN_RIGHT | wxALL, 10) self.SetSizer(vbs) self.SetAutoLayout(True) EVT_BUTTON(self, wxID_HELP, (lambda _, helpid = helpid: wxGetApp().displayhelpid(helpid))) import StringIO import traceback class ExceptionDialog(MyFixedScrolledMessageDialog): def __init__(self, frame, exception, title = 'Exception'): s = StringIO.StringIO() s.write('An unexpected exception has occurred.\nPlease see the help for details on what to do.\n\n') if hasattr(exception, 'gui_exc_info'): traceback.print_exception(exception.gui_exc_info[0], exception.gui_exc_info[1], exception.gui_exc_info[2], file = s) else: s.write('Exception with no extra info.\n%s\n' % (exception.str(),)) MyFixedScrolledMessageDialog.__init__(self, frame, s.getvalue(), title, helpids.ID_EXCEPTION_DIALOG) class MyStatusBar(wxStatusBar): def __init__(self, parent, id = -1): wxStatusBar.__init__(self, parent, id) self.sizechanged = False EVT_SIZE(self, self.OnSize) EVT_IDLE(self, self.OnIdle) self.gauge = wxGauge(self, 1000, 1) self.SetFieldsCount(4) self.SetStatusWidths([ 200, -5, 180, -20]) self.Reposition() def OnSize(self, _): self.Reposition() self.sizechanged = True def OnIdle(self, _): if self.sizechanged: self.Reposition() def Reposition(self): rect = self.GetFieldRect(2) self.gauge.SetPosition(wxPoint(rect.x + 2, rect.y + 2)) self.gauge.SetSize(wxSize(rect.width - 4, rect.height - 4)) self.sizeChanged = False def progressminor(self, pos, max, desc = ''): self.gauge.SetRange(max) self.gauge.SetValue(pos) self.SetStatusText(desc, 3) def progressmajor(self, pos, max, desc = ''): self.progressminor(0, 1) if len(desc) and max: str = '%d/%d %s' % (pos + 1, max, desc) else: str = desc self.SetStatusText(str, 1) class AlertDialogWithHelp(wxDialog): def __init__(self, parent, message, caption, helpfn, style = wxDEFAULT_DIALOG_STYLE, icon = wxICON_EXCLAMATION): wxDialog.__init__(self, parent, -1, caption, style = style | wxDEFAULT_DIALOG_STYLE) p = self hbs = wxBoxSizer(wxHORIZONTAL) hbs.Add(wxStaticBitmap(p, -1, wxArtProvider_GetBitmap(self.icontoart(icon), wxART_MESSAGE_BOX)), 0, wxCENTER | wxALL, 10) hbs.Add(wxStaticText(p, -1, message), 1, wxCENTER | wxALL, 10) buttsizer = self.CreateButtonSizer(wxHELP | style) vbs = wxBoxSizer(wxVERTICAL) vbs.Add(hbs, 1, wxEXPAND | wxALL, 10) vbs.Add(buttsizer, 0, wxCENTER | wxALL, 10) self.SetSizer(vbs) self.SetAutoLayout(True) vbs.Fit(self) EVT_BUTTON(self, wxID_HELP, helpfn) def icontoart(self, id): if id & wxICON_EXCLAMATION: return wxART_WARNING if id & wxICON_INFORMATION: return wxART_INFORMATION return wxART_INFORMATION class AnotherDialog(wxDialog): def __init__(self, parent, message, caption, buttons, helpfn = None, style = wxDEFAULT_DIALOG_STYLE, icon = wxICON_EXCLAMATION): wxDialog.__init__(self, parent, -1, caption, style = style) p = self hbs = wxBoxSizer(wxHORIZONTAL) hbs.Add(wxStaticBitmap(p, -1, wxArtProvider_GetBitmap(self.icontoart(icon), wxART_MESSAGE_BOX)), 0, wxCENTER | wxALL, 10) hbs.Add(wxStaticText(p, -1, message), 1, wxCENTER | wxALL, 10) buttsizer = wxBoxSizer(wxHORIZONTAL) for label, id in buttons: buttsizer.Add(wxButton(self, id, label), 0, wxALL | wxALIGN_CENTER, 5) if id != wxID_HELP: EVT_BUTTON(self, id, self.OnButton) continue EVT_BUTTON(self, wxID_HELP, helpfn) vbs = wxBoxSizer(wxVERTICAL) vbs.Add(hbs, 1, wxEXPAND | wxALL, 10) vbs.Add(buttsizer, 0, wxCENTER | wxALL, 10) self.SetSizer(vbs) self.SetAutoLayout(True) vbs.Fit(self) def OnButton(self, event): self.EndModal(event.GetId()) def icontoart(self, id): if id & wxICON_EXCLAMATION: return wxART_WARNING if id & wxICON_INFORMATION: return wxART_INFORMATION return wxART_INFORMATION